/**
 * Copyright (C) 2006 OQube 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 * author: Arnaud Bailly - abailly AT oqube DOT com
 * created: 14 juin 2006
 */
package speculoos.beans;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import speculoos.utils.TypeHelper;

/**
 * A structure encapsulating a bean for the purpose of using it in a mapper.
 * 
 * @author nono
 * 
 */
public class BeanMap implements MapStructure {

	private Class bean;

	private TypeHelper helper = new TypeHelper();

	/**
	 * Default constructor.
	 * 
	 */
	public BeanMap() {
	}

	/**
	 * Create with given class instance.
	 * 
	 * @param cls
	 *            may not be null.
	 */
	public BeanMap(Class cls) {
		this.bean = cls;
	}

	/**
	 * @return Returns the bean.
	 */
	public Class getBean() {
		return bean;
	}

	/**
	 * @param bean
	 *            The bean to set.
	 */
	public void setBean(Class bean) {
		this.bean = bean;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see speculoos.jndi.MapStructure#getFields()
	 */
	public Collection getFields() {
		return collectFields(bean);
	}

	private Collection collectFields(Class bean2) {
		BeanInfo info;
		List ret = new ArrayList();
		try {
			info = Introspector.getBeanInfo(bean2);
		} catch (IntrospectionException e) {
			return ret;
		}
		PropertyDescriptor[] props = info.getPropertyDescriptors();
		for (int i = 0; i < props.length; i++) {
			MapEntry me = new MapEntry(props[i].getName());
			me.setType(props[i].getPropertyType().getName());
			Object d = helper.getDefault(props[i].getPropertyType());
			me.setValue(d== null ? "null" : d.toString());
			ret.add(me);
		}
		return ret;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see speculoos.jndi.MapStructure#getName()
	 */
	public String getName() {
		return bean.getName();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see speculoos.jndi.MapStructure#getInheritedFields()
	 */
	public Collection getInheritedFields() {
		List ret = new ArrayList();
		if (bean.isInterface())
			collectInherited(bean, ret);
		return ret;
	}

	/*
	 * recursive method for collecting the inherited fieds from a hirarchy of
	 * interfaces. Given class is expected to be an interface.
	 */
	private void collectInherited(Class bean2, List ret) {
		// add bean fields
		if (bean2 != bean)
			ret.addAll(collectFields(bean2));
		Class[] sups = bean2.getInterfaces();
		for (int i = 0; i < sups.length; i++) {
			// recurse
			collectInherited(sups[i], ret);
		}
	}

	/**
	 * Returns whether or not this class is a concrete class.
	 * 
	 * @return true if this class not abstract.
	 */
	public boolean isConcrete() {
		return !Modifier.isAbstract(bean.getModifiers());
	}
}
